﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;

namespace Scrabble.Model
{
    [ContractClass(typeof(CodeContractForIGame))]
    public interface IGame
    {
        event EventHandler ActivePlayerChanged;
        event EventHandler PoolChanged;
        event EventHandler GameOver;

        ITimeKeeper TimeKeeper { get; set; }

        Board Board
        {
            get;
        }

        IEnumerable<TileStatistics> TileUsage
        {
            get;
        }

        IEnumerable<IGameEvent> EventLog
        {
            get;
        }

        IEnumerable<IPlayer> Players
        {
            get;
        }

        IPlayer ActivePlayer { get; }

        bool IsGameOver { get; }

        bool IsPlacementValid(PlayVector at);

        int ScorePlacement(IEnumerable<Tile> tiles, PlayVector at);

        IEnumerable<IList<TileInPlay>> SetOfWordsFormedBy(IEnumerable<Tile> tiles, PlayVector at);

        StateOfPlay StateOfPlay
        {
            get;
        }
    }

    [ContractClassFor(typeof(IGame))]
    public abstract class CodeContractForIGame : IGame
    {
#pragma warning disable 0067
        public event EventHandler ActivePlayerChanged;
        public event EventHandler PoolChanged;
        public event EventHandler GameOver;
#pragma warning restore 0067

        public ITimeKeeper TimeKeeper
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        public Board Board
        {
            get
            {
                Contract.Ensures(Contract.Result<Board>() != null);
                throw new NotImplementedException();
            }
        }

        public IEnumerable<TileStatistics> TileUsage
        {
            get
            {
                Contract.Ensures(Contract.Result<IEnumerable<TileStatistics>>() != null);
                throw new NotImplementedException();
            }
        }

        public IEnumerable<IGameEvent> EventLog
        {
            get
            {
                Contract.Ensures(Contract.Result<IEnumerable<IGameEvent>>() != null);
                throw new NotImplementedException();
            }
        }

        public IEnumerable<IPlayer> Players
        {
            get
            {
                Contract.Ensures(Contract.Result<IEnumerable<IPlayer>>() != null);
                throw new NotImplementedException();
            }
        }

        public IPlayer ActivePlayer
        {
            get { throw new NotImplementedException(); }
        }

        public bool IsGameOver
        {
            get { throw new NotImplementedException(); }
        }

        public bool IsPlacementValid(PlayVector at)
        {
            Contract.Requires<ArgumentNullException>(at != null);
            Contract.Requires<ArgumentOutOfRangeException>(at.StartingLocation.IsWithinBounds);
            return default(bool);
        }

        public int ScorePlacement(IEnumerable<Tile> tiles, PlayVector at)
        {
            Contract.Requires<ArgumentNullException>(tiles != null);
            Contract.Requires<ArgumentNullException>(at != null);
            Contract.Ensures(Contract.Result<int>() >= 0);

            return default(int);
        }

        public IEnumerable<IList<TileInPlay>> SetOfWordsFormedBy(IEnumerable<Tile> tiles, PlayVector at)
        {
            Contract.Requires<ArgumentNullException>(tiles != null);
            Contract.Requires<ArgumentNullException>(at != null);
            Contract.Ensures(Contract.Result<IEnumerable<IList<TileInPlay>>>() != null);

            return default(IEnumerable<IList<TileInPlay>>);
        }

        public StateOfPlay StateOfPlay
        {
            get
            {
                Contract.Ensures(Contract.Result<StateOfPlay>() != null);
                return default(StateOfPlay);
            }
        }
    }
}